package cn.virens.common.util.core.network;

import cn.virens.common.util.core.Assert;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.convert.ConvertUtil;
import org.dromara.hutool.core.date.DateFormatPool;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.split.SplitUtil;
import org.dromara.hutool.core.util.ObjUtil;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;

/**
 * HttpRequest 工具类
 *
 * @author : virens
 */
public class RequestUtil {
    private static final String[] EMPTY = {};
    private static final String UNKNOWN = "unknown";

    /**
     * 获取request中的所有值
     *
     * @param request 请求对象
     * @return map value
     */
    public static Map<String, String[]> getParam(HttpServletRequest request) {
        return Assert.isNull(request).getParameterMap();
    }

    /**
     * 获取request中的所有值
     *
     * @param request 请求对象
     * @return map value
     */
    public static Map<String, String> getParam0(HttpServletRequest request) {
        Map<String, String> result = new HashMap<>();

        Map<String, String[]> map = getParam(request);
        for (Entry<String, String[]> entry : map.entrySet()) {
            result.put(entry.getKey(), ArrayUtil.join(entry.getValue(), ","));
        }

        return result;
    }

    /**
     * 根据默认值返回对应的类型值
     *
     * @param <T>        class
     * @param request    请求对象
     * @param columnName 字段名
     * @param defValue   默认值
     * @return T value
     */
    public static <T> T getValue(HttpServletRequest request, String columnName, T defValue) {
        return ConvertUtil.convertQuietly(defValue.getClass(), getValueStr(request, columnName), defValue);
    }

    /**
     * 返回对应的类型
     *
     * @param <T>        class
     * @param request    请求对象
     * @param columnName 字段名
     * @param clazz      类型
     * @return T value
     */
    public static <T> T getValue(HttpServletRequest request, String columnName, Class<T> clazz) {
        return ConvertUtil.convertQuietly(clazz, getValueStr(request, columnName));
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return String array
     */
    public static String[] getValue(HttpServletRequest request, String columnName) {
        return ObjUtil.defaultIfNull(request.getParameterValues(columnName), EMPTY);
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return string value
     */
    public static String getValueStr(HttpServletRequest request, String columnName) {
        return getValueStr(request, columnName, null);
    }

    /**
     * 在request中根据name查找值,如找不到就返回默认值
     *
     * @param request      请求对象
     * @param columnName   参数名
     * @param defaultValue 默认值
     * @return string value
     */
    public static String getValueStr(HttpServletRequest request, String columnName, String defaultValue) {
        String sValue = request.getParameter(columnName);
        if (sValue == null || sValue.isEmpty()) {
            return defaultValue;
        } else {
            return sValue;
        }
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return integer value
     */
    public static Integer getValueInt(HttpServletRequest request, String columnName) {
        return getValueInt(request, columnName, 0);
    }

    /**
     * 在request中根据name查找值,如找不到就返回默认值
     *
     * @param request      请求对象
     * @param columnName   参数名
     * @param defaultValue 默认值
     * @return integer
     */
    public static Integer getValueInt(HttpServletRequest request, String columnName, Integer defaultValue) {
        return ConvertUtil.toInt(getValueStr(request, columnName), defaultValue);
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return long value
     */
    public static Long getValueLong(HttpServletRequest request, String columnName) {
        return getValueLong(request, columnName, 0L);
    }

    /**
     * 在request中根据name查找值,如找不到就返回默认值
     *
     * @param request      请求对象
     * @param columnName   参数名
     * @param defaultValue 默认值
     * @return long value
     */
    public static Long getValueLong(HttpServletRequest request, String columnName, Long defaultValue) {
        return ConvertUtil.toLong(getValueStr(request, columnName), defaultValue);
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return double value
     */
    public static Double getValueDouble(HttpServletRequest request, String columnName) {
        return getValueDouble(request, columnName, 0D);
    }

    /**
     * 在request中根据name查找值,如找不到就返回默认值
     *
     * @param request      请求对象
     * @param columnName   参数名
     * @param defaultValue 默认值
     * @return doulbe value
     */
    public static Double getValueDouble(HttpServletRequest request, String columnName, Double defaultValue) {
        return ConvertUtil.toDouble(getValueStr(request, columnName), defaultValue);
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return float value
     */
    public static Float getValueFloat(HttpServletRequest request, String columnName) {
        return getValueFloat(request, columnName, 0F);
    }

    /**
     * 在request中根据name查找值,如找不到就返回默认值
     *
     * @param request      请求对象
     * @param columnName   参数名
     * @param defaultValue 默认值
     * @return float value
     */
    public static Float getValueFloat(HttpServletRequest request, String columnName, Float defaultValue) {
        return ConvertUtil.toFloat(getValueStr(request, columnName), defaultValue);
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return boolean value
     */
    public static Boolean getValueBoolean(HttpServletRequest request, String columnName) {
        return getValueBoolean(request, columnName, false);
    }

    /**
     * 在request中根据name查找值,如找不到就返回默认值
     *
     * @param request      请求对象
     * @param columnName   参数名
     * @param defaultValue 默认值
     * @return boolean vlaue
     */
    public static Boolean getValueBoolean(HttpServletRequest request, String columnName, Boolean defaultValue) {
        return ConvertUtil.toBoolean(getValueStr(request, columnName), defaultValue);
    }

    /**
     * 获取 - 时间
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return Date对象
     */
    public static Date getValueDate(HttpServletRequest request, String columnName) {
        return getValueDate(request, columnName, DateFormatPool.NORM_DATETIME_PATTERN, null);
    }

    /**
     * 获取 - 时间
     *
     * @param request    请求对象
     * @param columnName 变量名
     * @param format     时间格式
     * @return Date对象, 默认当前时间
     */
    public static Date getValueDate(HttpServletRequest request, String columnName, String format) {
        return getValueDate(request, columnName, format, new Date());
    }

    /**
     * 获取 - 时间
     *
     * @param request      请求对象
     * @param columnName   变量名
     * @param format       时间格式
     * @param defaultValue 默认值
     * @return Date对象
     */
    public static Date getValueDate(HttpServletRequest request, String columnName, String format, Date defaultValue) {
        return get(request, columnName, defaultValue, (sValue) -> DateUtil.parse(sValue, format));
    }

    /**
     * 获取 - 时间(LocalTime)
     *
     * @param request    请求对象
     * @param columnName 变量名
     * @return LocalDate对象
     */
    public static LocalTime getValueLocalTime(HttpServletRequest request, String columnName) {
        return getValueLocalTime(request, columnName, DateFormatPool.NORM_TIME_PATTERN, null);
    }

    /**
     * 获取 - 时间(LocalTime)
     *
     * @param request    请求对象
     * @param columnName 变量名
     * @param format     时间格式
     * @return LocalDate对象
     */
    public static LocalTime getValueLocalTime(HttpServletRequest request, String columnName, String format) {
        return getValueLocalTime(request, columnName, format, null);
    }

    /**
     * 获取 - 时间(LocalTime)
     *
     * @param request      请求对象
     * @param columnName   变量名
     * @param format       时间格式
     * @param defaultValue 默认值
     * @return LocalDate对象
     */
    public static LocalTime getValueLocalTime(HttpServletRequest request, String columnName, String format, LocalTime defaultValue) {
        return get(request, columnName, defaultValue, (sValue) -> LocalTime.parse(sValue, DateTimeFormatter.ofPattern(format)));
    }

    /**
     * 获取 - 时间(LocalDate)
     *
     * @param request    请求对象
     * @param columnName 变量名
     * @return LocalDate对象
     */
    public static LocalDate getValueLocalDate(HttpServletRequest request, String columnName) {
        return getValueLocalDate(request, columnName, DateFormatPool.NORM_DATE_PATTERN, null);
    }

    /**
     * 获取 - 时间(LocalDate)
     *
     * @param request    请求对象
     * @param columnName 变量名
     * @param format     时间格式
     * @return LocalDate对象
     */
    public static LocalDate getValueLocalDate(HttpServletRequest request, String columnName, String format) {
        return getValueLocalDate(request, columnName, format, null);
    }

    /**
     * 获取 - 时间(LocalDate)
     *
     * @param request      请求对象
     * @param columnName   变量名
     * @param format       时间格式
     * @param defaultValue 默认值
     * @return LocalDate对象
     */
    public static LocalDate getValueLocalDate(HttpServletRequest request, String columnName, String format, LocalDate defaultValue) {
        return get(request, columnName, defaultValue, (sValue) -> LocalDate.parse(sValue, DateTimeFormatter.ofPattern(format)));
    }

    /**
     * 获取 - 时间(LocalDateTime)
     *
     * @param request    请求对象
     * @param columnName 变量名
     * @return LocalDate对象
     */
    public static LocalDateTime getValueLocalDateTime(HttpServletRequest request, String columnName) {
        return getValueLocalDateTime(request, columnName, DateFormatPool.NORM_DATETIME_PATTERN, null);
    }

    /**
     * 获取 - 时间(LocalDateTime)
     *
     * @param request    请求对象
     * @param columnName 变量名
     * @param format     时间格式
     * @return LocalDate对象
     */
    public static LocalDateTime getValueLocalDateTime(HttpServletRequest request, String columnName, String format) {
        return getValueLocalDateTime(request, columnName, format, null);
    }

    /**
     * 获取 - 时间(LocalDateTime)
     *
     * @param request      请求对象
     * @param columnName   变量名
     * @param format       时间格式
     * @param defaultValue 默认值
     * @return LocalDateTime对象
     */
    public static LocalDateTime getValueLocalDateTime(HttpServletRequest request, String columnName, String format, LocalDateTime defaultValue) {
        return get(request, columnName, defaultValue, (sValue) -> LocalDateTime.parse(sValue, DateTimeFormatter.ofPattern(format)));
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return JSONObject value
     */
    public static JSONObject getValueJSONObj(HttpServletRequest request, String columnName) {
        return JSON.parseObject(getValueStr(request, columnName));
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return JSONArray value
     */
    public static JSONArray getValueJSONArr(HttpServletRequest request, String columnName) {
        return JSON.parseArray(getValueStr(request, columnName));
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @return string list value
     */
    public static List<String> getValueList(HttpServletRequest request, String columnName) {
        return ListUtil.of(getValue(request, columnName));
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @param separator  参数名
     * @return string list value
     */
    public static List<String> getValueList(HttpServletRequest request, String columnName, String separator) {
        return SplitUtil.split(getValueStr(request, columnName), separator);
    }

    /**
     * 在request中根据name查找值
     *
     * @param request    请求对象
     * @param columnName 参数名
     * @param separator  参数名
     * @return string array value
     */
    public static String[] getValueArr(HttpServletRequest request, String columnName, String separator) {
        return SplitUtil.splitToArray(getValueStr(request, columnName), separator);
    }


    /**
     * 获取请求ContentType
     *
     * @param request 请求对象
     * @return content type
     */
    public static String getContentType(HttpServletRequest request) {
        return request.getContentType();
    }

    /**
     * 获取请求HTTP头
     *
     * @param request 请求对象
     * @param header  header's name
     * @return header's value
     */
    public static String getHeader(HttpServletRequest request, String header) {
        return StrUtil.isEmpty(header) ? null : request.getHeader(header);
    }

    /**
     * 获取请求类型
     *
     * @param request 请求对象
     * @return method type
     */
    public static String getMethod(HttpServletRequest request) {
        return request.getMethod();
    }

    /**
     * 获取Session
     *
     * @param request 请求对象
     * @return session object
     */
    public static HttpSession getSession(HttpServletRequest request) {
        return request.getSession();
    }

    /**
     * 获取根据名字获取Session值
     *
     * @param request 请求对象
     * @param name    session's name
     * @return session's value
     */
    public static Object getSession(HttpServletRequest request, String name) {
        return getSession(request).getAttribute(name);
    }

    /**
     * 获取Cookie
     *
     * @param request 请求对象
     * @return cookie array
     */
    public static Cookie[] getCookies(HttpServletRequest request) {
        Cookie[] answer = Assert.isNull(request).getCookies();
        if (answer == null) return new Cookie[]{};

        return answer;
    }

    /**
     * 获取根据名字获取Cookie值
     *
     * @param request 请求对象
     * @param name    cookie's name
     * @return cookie's value
     */
    public static String getCookies(HttpServletRequest request, String name) {
        for (Cookie cookie : getCookies(request)) {
            if (equals(name, cookie.getName())) {
                return cookie.getValue();//
            }
        }

        return null;
    }

    /**
     * 获取请求的协议
     *
     * @param request 请求对象
     * @return request scheme
     */
    public static String getRequestScheme(HttpServletRequest request) {
        String scheme = request.getHeader("X-Forwarded-Scheme");

        if (scheme == null || scheme.isEmpty()) {
            return request.getScheme();
        } else {
            return scheme;
        }
    }

    /**
     * 获取本机Host
     *
     * @param request 请求对象
     * @return host
     */
    public static String getRequestHost(HttpServletRequest request) {
        String host = request.getHeader("X-Forwarded-Host");
        if (host == null || host.isEmpty()) {
            host = request.getHeader("Host");
        }

        if (StrUtil.startWithIgnoreCase(host, "http://")) {
            return StrUtil.sub(host, 0, host.length() - 3);
        }

        if (StrUtil.startWithIgnoreCase(host, "https://")) {
            return StrUtil.sub(host, 0, host.length() - 4);
        }

        return host;
    }

    /**
     * 获取 请求地址
     *
     * @param request 请求对象
     * @return request uri
     */
    public static String getRequestURI(HttpServletRequest request) {
        return getRequestScheme(request) + "://" + getRequestHost(request);
    }

    /**
     * 获取当前请求地址
     *
     * @param request 请求对象
     * @return request url
     */
    public static String getRequestURL(HttpServletRequest request) {
        String queryString = request.getQueryString();
        String requestURI = request.getRequestURI();

        if (queryString != null && !queryString.isEmpty()) {
            return requestURI + "?" + queryString;
        } else {
            return requestURI;
        }
    }

    /**
     * 获取工程路径
     *
     * @param request 请求对象
     * @return dir
     */
    public static String getRealPath(HttpServletRequest request) {
        return getRealPath(request, "/");
    }

    /**
     * 根据request获取相对路径在web项目中的完整地址 request请求
     *
     * @param request  请求对象
     * @param filepath 项目中的相对于contextPath的相对路径
     * @return 项目所在路径 + 相对路径的完整地址
     */
    public static String getRealPath(HttpServletRequest request, String filepath) {
        return request.getServletContext().getRealPath(filepath);
    }

    /**
     * 获取远端IP
     *
     * @param request 请求对象
     * @return remote ip
     */
    public static String getRemoteAddr(HttpServletRequest request) {
        String address = request.getHeader("X-Forwarded-For");

        if (StrUtil.isEmpty(address) || equals(address, UNKNOWN)) {
            address = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StrUtil.isEmpty(address) || equals(address, UNKNOWN)) {
            address = request.getHeader("Proxy-Client-IP");
        }
        if (StrUtil.isEmpty(address) || equals(address, UNKNOWN)) {
            address = request.getHeader("X-Real-IP");
        }
        if (StrUtil.isEmpty(address) || equals(address, UNKNOWN)) {
            address = request.getRemoteAddr();
        }

        return StrUtil.subBefore(address, ",", false);
    }

    /**
     * 获取请求参数
     *
     * @param <T>          返回数据类型
     * @param request      请求对象
     * @param columnName   变量名
     * @param defaultValue 默认值
     * @param fun          格式转换
     * @return T对象
     */
    private static <T> T get(HttpServletRequest request, String columnName, T defaultValue, Function<String, T> fun) {
        String sValue = getValueStr(request, columnName);
        if (sValue != null && !sValue.isEmpty()) {
            try {
                return fun.apply(sValue);
            } catch (Throwable e) {
            }
        }

        return defaultValue;
    }

    /**
     * 判断2个字符串是否相同
     *
     * @param str1 字符串1
     * @param str2 字符串2
     * @return 是否相同
     */
    private static boolean equals(String str1, String str2) {
        return str1 != null && str1.equalsIgnoreCase(str2);
    }
}
